﻿/*
 * Erstellt mit SharpDevelop.
 * Benutzer: Kai Patrick
 * Datum: 24.04.2008
 * Zeit: 15:33
 * 
 * Sie können diese Vorlage unter Extras > Optionen > Codeerstellung > Standardheader ändern.
 */

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml;
using System.IO;
using System.Xml.Linq;

namespace Gamadus.Core
{
	/// <summary>
	/// Represents a Gamadus project
	/// </summary>
	public class Project
	{
		static readonly public int Version = 010;
		static public string VersionString
		{
			get
			{
				return String.Format(System.Globalization.CultureInfo.InvariantCulture,"{0:000}",Version).Insert(2,".").Insert(1,".");
			}
		}
		
		Dictionary<Resources.Type, Resources.Group> group = new Dictionary<Resources.Type, Resources.Group>();
		Dictionary<Resources.Type, int> nextId = new Dictionary<Resources.Type, int>();
		Dictionary<Resources.Type, Type> types = new Dictionary<Resources.Type, Type>();
		
		/// <summary>
		/// Get the next ID for a specified resource type
		/// </summary>
		public Dictionary<Resources.Type, int> NextId
		{
			get
			{
				return nextId;
			}
		}
		
		public ActionManager ActionMgr
		{
			get
			{
				return actionMgr;
			}
		}
		ActionManager actionMgr = new ActionManager();
		
		/// <summary>
		/// Standard cunstructor for a new empty project
		/// </summary>
		public Project()
		{
			foreach(Resources.Type type in Enum.GetValues(typeof(Resources.Type)))
			{
				group[type] = new Resources.Group(type);
				nextId[type] = 0;
			}
			
			types[Resources.Type.Object] = typeof(Resources.Object);
//			types[Resources.Type.Room] = typeof(Resources.Room);
//			types[Resources.Type.Sprite] = typeof(Resources.Sprite);
//			types[Resources.Type.Background] = typeof(Resources.Background);
//			types[Resources.Type.Class] = typeof(Resources.ClassResource);
		}
		
		/// <summary>
		/// Creates a new project and loads a project file
		/// </summary>
		/// <param name="file">The file to load</param>
		public Project(string file) : this()
		{
			Load(file);
		}
		
		/// <summary>
		/// Creates a new project and loads a project file
		/// </summary>
		/// <param name="file">The file to load</param>
		/// <returns>The project created</returns>
		public static Project Open(string file)
		{
			var project = new Project();
			project.Load(file);
			return project;
		}
		
		void Load(string file)
		{
			//TODO: load from zip
			var settings = new XmlReaderSettings();
			settings.ValidationType = ValidationType.Schema;
			string path = Path.Combine(Path.Combine(System.Windows.Forms.Application.StartupPath,"data"),"game.xsd");
			if(!File.Exists(path))
				throw new FileNotFoundException();
			settings.Schemas.Add("", path);
			XDocument xml;
			using(FileStream stream = new FileStream(file, FileMode.Open))
			{
				var reader = XmlReader.Create(stream,settings);
				while (reader.Read()) { };
				stream.Seek(0, SeekOrigin.Begin);
				xml = XDocument.Load(new StreamReader(stream));
				stream.Close();
			}
			Console.WriteLine(xml);
			var version = (string)xml.Element("gamadusProject").Attribute("version");
			
			XElement resources = xml.Element("gamadusProject").Element("resources");
			
			LoadResources(resources.Element("objects"), Resources.Type.Object);
			LoadResources(resources.Element("rooms"), Resources.Type.Room);
		}
		
		void LoadResources(XElement element, Resources.Type type)
		{
			nextId[type] = (int)element.Attribute("nextId");
			group[type] = LoadGroup(element, new Resources.Group(type));
		}
		
		Resources.Group LoadGroup(XElement element, Resources.Group grp)
		{
			//load resources in group
			foreach(XElement e in element.Descendants("resource"))
			{
				//create a new resource of the given type
				var res = (Resources.Resource)System.Activator.CreateInstance(types[grp.Type], (int)e.Attribute("id"), (string)e.Attribute("name"), this);
				//read the settings
				foreach(XElement setting in e.Element("settings").Elements())
				{
					var key = (string)setting.Attribute("name");
					object value = null;
					switch(setting.Name.ToString())
					{
						case "string":
							value = setting.Value;
							break;
						case "double":
							value = double.Parse(setting.Value, System.Globalization.CultureInfo.InvariantCulture);
							break;
						case "bool":
							value = bool.Parse(setting.Value);
							break;
						case "color":
							value = System.Drawing.ColorTranslator.FromHtml("#"+setting.Value);
							break;
					}
					res.Settings[key] = value;
					Console.WriteLine(key +" => "+value);
				}
				//read the type specific data
				res.ReadXml(e);
			}
			
			//load subgroups recursively
			foreach(XElement e in element.Descendants("group"))
				grp.AddNode(LoadGroup(e, new Resources.Group((string)e.Attribute("name"),grp.Type)));
			
			return grp;
		}
		
		/// <summary>
		/// Saves the project to a file
		/// </summary>
		/// <param name="file">The file to save it to</param>
		public void Save(string file)
		{
			throw new NotImplementedException();
		}
		
		/// <summary>
		/// Checks whether a resource name already exists in the project
		/// </summary>
		/// <param name="name">The resource name</param>
		/// <returns>Whether it exists</returns>
		public bool ResourceNameExists(string name)
		{
			return ResourceNameExists(name, null);
		}
		
		/// <summary>
		/// Checks whether a resource name already exists in the project
		/// </summary>
		/// <param name="name">The resource name</param>
		/// <param name="skip">A resource to skip checking</param>
		/// <returns>Whether it exists</returns>
		public bool ResourceNameExists(string name, Resources.Resource skip)
		{
			foreach(Resources.Group grp in group.Values)
			{
				if(grp.ResourceNameExists(name, skip))
					return true;
			}
			return false;
		}
		
		/// <summary>
		/// Checks whether a resource name is valid and does not exist
		/// </summary>
		/// <param name="name">The resource name</param>
		/// <returns>Whether it's valid</returns>
		public bool IsValidName(string name)
		{
			return (Regex.IsMatch(name,"^[_a-zA-Z]+[_a-zA-Z0-9]*$") && !ResourceNameExists(name));	
		}
		
		/// <summary>
		/// Checks whether a resource name is valid and does not exists
		/// </summary>
		/// <param name="name">The resource name</param>
		/// <param name="skip">A resource to skip checking</param>
		/// <returns>Whether it's valid</returns>
		public bool IsValidName(string name, Resources.Resource skip)
		{
			return (Regex.IsMatch(name,"^[_a-zA-Z]+[_a-zA-Z0-9]*$") && !ResourceNameExists(name, skip));
		}
		
		/// <summary>
		/// Checks a string for valid integer format
		/// </summary>
		/// <param name="name">The string to check</param>
		/// <returns>Whether it's valid</returns>
		public static bool IsValidInteger(string name)
		{
			return Regex.IsMatch(name,"^[-]?[0-9]+$");
		}
		
		/// <summary>
		/// Checks a string for valid positive integer format
		/// </summary>
		/// <param name="name">The string to check</param>
		/// <returns>Whether it's valid</returns>
		public static bool IsValidPositiveInteger(string name)
		{
			return Regex.IsMatch(name,"^[1-9]+[0-9]*$");
		}
	}
}
